package com.neo.tiny.secrity.filter;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.neo.tiny.common.enums.UserTypeEnum;
import com.neo.tiny.secrity.service.ClientDetailsService;
import com.neo.tiny.token.store.OAuth2AccessToken;
import com.neo.tiny.token.store.TokenStore;
import com.neo.tiny.token.context.TokenAuthentication;
import com.neo.tiny.secrity.util.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description:
 * @Author: yqz
 * @CreateDate: 2022/11/13 16:31
 */
@Slf4j
@Component
public class RedisAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private TokenStore tokenStore;

    @Resource(name = "userDetailsService")
    private UserDetailsService userDetailsService;

    @Resource(name = "clientDetailsService")
    private ClientDetailsService clientDetailsService;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        log.info("token过滤器:{}", request.getRequestURL());
        String token = SecurityUtils.obtainHeaderToken(request);
        if (StrUtil.isNotBlank(token)) {
            // 根据token 获取用户信息
            OAuth2AccessToken accessToken = tokenStore.getAccessToken(token);
            if (BeanUtil.isNotEmpty(accessToken)) {
                // 普通用户
                if (!UserTypeEnum.isClient(accessToken.getUserType())) {
                    UserDetails userDetails = userDetailsService.loadUserByUsername(accessToken.getUserName());
                    TokenAuthentication tokenAuthentication = new TokenAuthentication(userDetails, userDetails,
                            accessToken.getUserType(), accessToken.getClientId());
                    tokenAuthentication.setAuthenticated(true);
                    tokenAuthentication.setAuthorities(userDetails.getAuthorities());
                    tokenAuthentication.setScopes(accessToken.getScopes());
                    log.info("已认证的用户：{}", accessToken.getUserName());
                    //重新把认证添加到上下文中
                    SecurityContextHolder.getContext().setAuthentication(tokenAuthentication);

                    // 如果是oAuth 2 客户端模式获取的token
                } else if (UserTypeEnum.isClient(accessToken.getUserType())) {
                    UserDetails userDetails = clientDetailsService.loadUserByUsername(accessToken.getClientId());
                    TokenAuthentication tokenAuthentication = new TokenAuthentication(userDetails, userDetails,
                            accessToken.getUserType(), accessToken.getClientId());
                    tokenAuthentication.setAuthenticated(true);
                    tokenAuthentication.setClientId(accessToken.getClientId());
                    tokenAuthentication.setUserType(accessToken.getUserType());
                    tokenAuthentication.setScopes(accessToken.getScopes());
                    //重新把认证添加到上下文中
                    SecurityContextHolder.getContext().setAuthentication(tokenAuthentication);
                }
            }
        }

        filterChain.doFilter(request, response);
    }
}
